import { isEmpty } from "lodash"
import * as THREE from "three"
import { OrbitControls } from "three-orbitcontrols-ts"
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js"
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js"
import { FBXLoader } from "three/examples/jsm/loaders/FBXLoader.js"
import { STLLoader } from "three/examples/jsm/loaders/STLLoader.js"
import { TDSLoader } from "three/examples/jsm/loaders/TDSLoader.js"
import { onMounted, onUnmounted, ref, Ref } from "vue"
import { markRaw } from 'vue'

export function useThreeJs(threeContainer: Ref<HTMLDivElement | null>, modelPath: string | undefined) {
  const scene = ref<THREE.Scene | undefined>(undefined)
  const camera = ref<THREE.PerspectiveCamera | undefined>(undefined)
  const renderer = ref<THREE.WebGLRenderer | undefined>(undefined)
  const controls = ref<OrbitControls | undefined>(undefined)
  const model = ref<THREE.Group | undefined>(undefined)
  const animateId = ref<number | undefined>(undefined)
  const path = ref<string | undefined>(modelPath)

  // 添加模型加载进度回调函数
  let progressCallback: ((progress: number) => void) | null = null

  // 添加模型缩放状态
  const modelScaleFactor = ref<number>(1)
  const initialScale = ref<THREE.Vector3>(new THREE.Vector3(1, 1, 1))
  const baseTargetSize = ref<number>(4) // 基础目标尺寸

  path.value = modelPath

  // 用于确保模型完全在视图内的函数
  const fitCameraToModel = (modelBox: THREE.Box3) => {
    if (!camera.value || !threeContainer.value) return

    // 计算模型的尺寸和中心
    const size = modelBox.getSize(new THREE.Vector3())
    const center = modelBox.getCenter(new THREE.Vector3())

    // 计算最大维度
    const maxDim = Math.max(size.x, size.y, size.z)

    // 计算视野角度的一半(弧度)
    const fov = camera.value.fov * Math.PI / 180

    // 计算合适的相机距离
    // 在此距离下，模型将完全可见，并且有一些边距
    // 使用1.4作为系数可以在模型周围留出一些空间
    let cameraDistance = (maxDim / 2) / Math.tan(fov / 2) * 1.4

    // 设置相机位置，保持向下45度角观察
    camera.value.position.set(
      cameraDistance * 0.8, // 稍微偏离正面，以获得更好的3D效果
      cameraDistance * 0.6,
      cameraDistance * 0.8
    )

    // 将相机对准模型中心
    camera.value.lookAt(center.x, center.y, center.z)

    // 更新控制器目标为模型中心
    if (controls.value) {
      controls.value.target.copy(center)
      controls.value.update()
    }
  }

  // 根据文件扩展名获取适当的加载器
  const getLoader = (modelPath: string) => {
    const extension = modelPath.toLowerCase().split('.').pop() || '';

    switch (extension) {
      case 'obj':
        return new OBJLoader();
      case 'fbx':
        return {
          load: (url: string, onLoad: (result: THREE.Object3D) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void) => {
            const loader = new FBXLoader();
            loader.load(
              url,
              (object) => {
                onLoad(object);
              },
              onProgress,
              (error) => {
                if (onError) onError(error);
              }
            );
          }
        };
      case 'stl':
        return {
          load: (url: string, onLoad: (result: THREE.Object3D) => void, onProgress?: (event: ProgressEvent) => void, onError?: (event: ErrorEvent) => void) => {
            const loader = new STLLoader();
            loader.load(url,
              (geometry) => {
                const material = new THREE.MeshStandardMaterial({ color: 0xaaaaaa, metalness: 0.25, roughness: 0.4 });
                const mesh = new THREE.Mesh(geometry, material);
                onLoad(mesh);
              },
              onProgress,
              onError
            );
          }
        };
      case '3ds':
        return new TDSLoader();
      case 'gltf':
      case 'glb':
      default:
        return new GLTFLoader();
    }
  };

  // 处理不同格式模型的加载结果
  const processLoadedModel = (loadedModel: THREE.Object3D) => {
    if (!scene.value || !camera.value || !threeContainer.value) return;

    const currentScene = scene.value;

    // 创建一个新的组来包含模型
    const modelGroup = new THREE.Group();
    currentScene.add(modelGroup);

    // 将模型添加到组中
    modelGroup.add(loadedModel);

    // 计算模型的包围盒
    const box = new THREE.Box3().setFromObject(loadedModel);
    const size = box.getSize(new THREE.Vector3());
    const center = box.getCenter(new THREE.Vector3());

    // 获取容器尺寸
    const containerWidth = threeContainer.value.clientWidth;
    const containerHeight = threeContainer.value.clientHeight;

    // 获取模型最大维度
    const maxDimension = Math.max(size.x, size.y, size.z);
    // 容器的最小维度，留出10%的边距
    const containerMinDimension = Math.min(containerWidth, containerHeight) * 0.85;

    // 计算缩放因子，确保模型适合容器
    let scaleFactor = containerMinDimension / maxDimension;

    // 智能调整模型大小
    if (maxDimension < 1) {
      // 小模型放大
      scaleFactor = Math.max(scaleFactor, 4);
    } else if (maxDimension > 10) {
      // 大模型缩小，但确保仍然可见
      scaleFactor = Math.min(scaleFactor, maxDimension / 4);
    }

    // 保存初始缩放值，用于后续鼠标滚轮缩放
    initialScale.value = new THREE.Vector3(scaleFactor, scaleFactor, scaleFactor);

    // 调整模型位置，使其中心点与原点对齐
    loadedModel.position.set(
      -center.x,
      -center.y,
      -center.z
    );

    // 应用统一缩放到组
    modelGroup.scale.copy(initialScale.value);

    model.value = modelGroup;

    // 计算模型的新边界框，用于定位相机
    const newBox = new THREE.Box3().setFromObject(modelGroup);

    // 调整相机位置，确保模型完全在视野内
    fitCameraToModel(newBox);

    // 添加鼠标滚轮事件监听器
    setupWheelZoom();

    startAnimation();
  };

  const initModel = () => {
    if (!path.value || !scene.value || !camera.value || !threeContainer.value) return;

    const fullPath = `/model-api${path.value}`;

    // 获取文件扩展名
    const extension = path.value.toLowerCase().split('.').pop() || '';

    const loader = getLoader(path.value);

    // 通用进度处理函数
    const handleProgress = (event: ProgressEvent) => {
      if (event.lengthComputable && progressCallback) {
        // 计算加载进度百分比
        const progress = event.loaded / event.total;
        progressCallback(progress);
      }
    };

    // 检查是否是GLTF或GLB模型
    if (path.value.toLowerCase().endsWith('.gltf') || path.value.toLowerCase().endsWith('.glb')) {
      (loader as GLTFLoader).load(
        fullPath,
        (gltf) => {
          if (progressCallback) progressCallback(1); // 确保加载完成时进度为100%
          processLoadedModel(gltf.scene);
        },
        (progress) => {
          handleProgress(progress);
        },
        (error) => {
          console.error('Error loading GLTF/GLB model:', error);
        }
      );
    }
    // 特别处理FBX模型
    else if (extension === 'fbx') {
      // 确保FBX模型加载正确
      try {
        const fbxLoader = new FBXLoader();
        fbxLoader.load(
          fullPath,
          (object) => {
            if (progressCallback) progressCallback(1); // 确保加载完成时进度为100%
            processLoadedModel(object);
          },
          (progress) => {
            handleProgress(progress);
          },
          (error) => {
            console.error("FBX模型加载失败", error);
          }
        );
      } catch (error) {
        console.error("FBX loader初始化失败", error);
      }
    }
    else {
      // 处理其他类型的模型格式
      loader.load(
        fullPath,
        (loadedObject: any) => {
          if (progressCallback) progressCallback(1); // 确保加载完成时进度为100%

          // 检查是否是具有scene属性的GLTF对象
          if (loadedObject && loadedObject.scene) {
            processLoadedModel(loadedObject.scene);
          } else {
            // 否则直接处理对象本身（OBJ, FBX, STL等）
            processLoadedModel(loadedObject);
          }
        },
        (progress) => {
          handleProgress(progress);
        },
        (error) => {
          console.error(`Error loading model: ${error}`);
        }
      );
    }
  };

  // 添加鼠标滚轮缩放功能
  const setupWheelZoom = () => {
    if (!threeContainer.value || !model.value) return

    // 移除可能存在的旧事件监听器
    threeContainer.value.removeEventListener('wheel', handleWheel)

    // 添加新的事件监听器
    threeContainer.value.addEventListener('wheel', handleWheel, { passive: false })
  }

  // 处理鼠标滚轮事件
  const handleWheel = (event: WheelEvent) => {
    if (!model.value) return

    // 当使用Ctrl+滚轮时，控制模型大小而不是相机缩放
    if (event.ctrlKey) {
      event.preventDefault() // 防止页面滚动

      // 确定缩放方向和强度
      const delta = -event.deltaY * 0.001 // 负值使滚轮向上放大模型

      // 更新模型缩放因子
      modelScaleFactor.value *= (1 + delta)

      // 限制缩放范围，避免过大或过小
      modelScaleFactor.value = Math.max(0.2, Math.min(modelScaleFactor.value, 3))

      // 应用新的缩放
      if (model.value) {
        model.value.scale.x = initialScale.value.x * modelScaleFactor.value
        model.value.scale.y = initialScale.value.y * modelScaleFactor.value
        model.value.scale.z = initialScale.value.z * modelScaleFactor.value
      }
    }
  }

  const initThree = () => {
    if (!threeContainer.value) return

    // 创建场景
    const newScene = markRaw(new THREE.Scene())
    newScene.background = null
    scene.value = newScene

    // 设置容器尺寸
    threeContainer.value.style.width = '100%'
    threeContainer.value.style.minWidth = '300px'
    threeContainer.value.style.height = '400px'

    // 获取容器尺寸
    const containerWidth = threeContainer.value.clientWidth
    const containerHeight = threeContainer.value.clientHeight

    // 创建相机
    const newCamera = markRaw(new THREE.PerspectiveCamera(
      80, // 使用较小的FOV以减少透视变形
      containerWidth / containerHeight,
      0.1,
      1000
    ))

    // 初始相机位置，后面会根据模型调整
    newCamera.position.set(10, 5, 10)
    newCamera.lookAt(0, 0, 0)
    camera.value = newCamera

    // 创建渲染器
    const newRenderer = markRaw(new THREE.WebGLRenderer({
      antialias: true,
      alpha: true,
    }))

    // 增强光照
    const ambientLight = markRaw(new THREE.AmbientLight(0xffffff, 0.8))
    newScene.add(ambientLight)

    const directionalLight = markRaw(new THREE.DirectionalLight(0xffffff, 1.2))
    directionalLight.position.set(5, 5, 5)
    newScene.add(directionalLight)

    // 添加补充光源
    const backLight = markRaw(new THREE.DirectionalLight(0xffffff, 0.8))
    backLight.position.set(-5, 5, -5)
    newScene.add(backLight)

    // 添加底部光源，确保模型底部可见
    const bottomLight = markRaw(new THREE.DirectionalLight(0xffffff, 0.5))
    bottomLight.position.set(0, -5, 0)
    newScene.add(bottomLight)

    // 设置渲染尺寸
    if (containerWidth && containerHeight) {
      // 使用1.2倍渲染尺寸提高清晰度
      const renderWidth = Math.floor(containerWidth * 1.2)
      const renderHeight = Math.floor(containerHeight * 1.2)

      newRenderer.setSize(renderWidth, renderHeight)
      // 调整DOM元素样式以适应容器
      newRenderer.domElement.style.width = '100%'
      newRenderer.domElement.style.height = '100%'
    }

    threeContainer.value.appendChild(newRenderer.domElement)
    renderer.value = newRenderer

    // 设置控制器
    if (newCamera && newRenderer) {
      const newControls = markRaw(new OrbitControls(newCamera, newRenderer.domElement))
      newControls.enableDamping = true
      newControls.dampingFactor = 0.1

      // 添加控制器限制，防止模型旋转到看不见的角度
      newControls.minPolarAngle = 0.1 // 最小仰角
      newControls.maxPolarAngle = Math.PI - 0.1 // 最大仰角

      // 设置旋转中心为原点（加载模型后会更新）
      newControls.target.set(0, 0, 0)

      controls.value = newControls
    }

    // 重置缩放因子
    modelScaleFactor.value = 1

    initModel()
  }

  const animate = () => {
    const currentRenderer = renderer.value
    const currentScene = scene.value
    const currentCamera = camera.value
    const currentControls = controls.value

    if (!currentRenderer || !currentScene || !currentCamera) {
      stopAnimation()
      return
    }

    try {
      if (currentControls) {
        currentControls.update()
      }

      currentRenderer.render(currentScene, currentCamera)
      animateId.value = requestAnimationFrame(animate)
    } catch (error) {
      console.error('Animation error:', error)
      stopAnimation()
    }
  }

  const startAnimation = () => {
    stopAnimation()

    if (!renderer.value || !scene.value || !camera.value) return

    animateId.value = requestAnimationFrame(animate)
  }

  const stopAnimation = () => {
    if (animateId.value) {
      cancelAnimationFrame(animateId.value)
      animateId.value = undefined
    }
  }

  const updateModelUrl = (modelPath: string | undefined) => {
    if (isEmpty(modelPath)) {
      if (scene.value && model.value) {
        scene.value.remove(model.value)
        model.value = undefined
      }
      return
    }

    stopAnimation()

    // 完全清理之前的资源
    disposeThree()

    path.value = modelPath
    // 重新初始化Three.js环境
    initThree()
  }

  const handleResize = () => {
    if (!camera.value || !renderer.value || !threeContainer.value) return

    const width = threeContainer.value.clientWidth
    const height = threeContainer.value.clientHeight

    if (width && height) {
      // 更新相机视角
      camera.value.aspect = width / height
      camera.value.updateProjectionMatrix()

      // 保持1.2倍渲染尺寸
      const renderWidth = Math.floor(width * 1.2)
      const renderHeight = Math.floor(height * 1.2)

      renderer.value.setSize(renderWidth, renderHeight)

      // 如果有模型，确保它仍然完全可见
      if (model.value) {
        // 计算模型的新边界框
        const box = new THREE.Box3().setFromObject(model.value)

        // 重新调整相机位置
        fitCameraToModel(box)
      }
    }
  }

  const disposeThree = () => {
    stopAnimation()

    // 移除滚轮事件监听器
    if (threeContainer.value) {
      threeContainer.value.removeEventListener('wheel', handleWheel)
    }

    if (model.value) {
      scene.value?.remove(model.value)
      // 清理模型资源
      model.value.traverse((object) => {
        if (object instanceof THREE.Mesh) {
          if (object.geometry) {
            object.geometry.dispose()
          }
          if (object.material) {
            if (Array.isArray(object.material)) {
              object.material.forEach(material => material.dispose())
            } else {
              object.material.dispose()
            }
          }
        }
      })
      model.value = undefined
    }

    if (controls.value) {
      controls.value.dispose()
      controls.value = undefined
    }

    if (renderer.value) {
      if (threeContainer.value && threeContainer.value.contains(renderer.value.domElement)) {
        threeContainer.value.removeChild(renderer.value.domElement)
      }
      renderer.value.dispose()
      renderer.value = undefined
    }

    scene.value = undefined
    camera.value = undefined
  }

  // 设置加载进度回调
  const setProgressCallback = (callback: (progress: number) => void) => {
    progressCallback = callback;
  }

  onMounted(() => {
    initThree()
    window.addEventListener("resize", handleResize)
  })

  onUnmounted(() => {
    window.removeEventListener("resize", handleResize)
    // 确保移除滚轮事件监听器
    if (threeContainer.value) {
      threeContainer.value.removeEventListener('wheel', handleWheel)
    }
    disposeThree()
  })

  return {
    handleResize,
    updateModelUrl,
    setProgressCallback // 导出进度回调设置方法
  }
}
